package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.EamHierarchy;
import com.uinnova.product.eam.comm.model.es.EamMultiModelHierarchy;
import com.uinnova.product.eam.config.Env;
import com.uinnova.product.eam.model.EamArtifactRltVo;
import com.uinnova.product.eam.model.bm.ProductEle;
import com.uinnova.product.eam.model.dto.EamHierarchyDto;
import com.uinnova.product.eam.model.dto.EamMultiModelHierarchyDto;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.es.BmHierarchyDao;
import com.uino.bean.cmdb.base.LibType;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 层级配置实现
 *
 * @author ch
 * @date 2022/1/6
 */
@Slf4j
@Service
public class BmHierarchySvcImpl implements IBmHierarchySvc {


    private static final String THROW_MESSAGE = "层级配置已被更新，请刷新后查看！";
    private static final String SHAPE_FLAG = "0";

    private static final String ICON = "icon";

    private static final String MODEL_ID = "modelId";
    private static final String DIR_LEL = "dirLvl";

    @Resource
    BmHierarchyDao bmHierarchyDao;

    @Autowired
    private ICISwitchSvc ciSwitchSvc;
    @Resource
    private EamCategorySvc categorySvc;
    @Resource
    private BmDiagramSvc diagramSvc;

    @Resource
    private IamsCIRltSwitchSvc rltSwitchSvc;

    @Autowired
    private IBmHierarchySvc iBmHierarchySvc;
    @Resource
    private IBmMultiModelHierarchySvc modelHierarchySvc;
    @Value("${http.resource.space}")
    private String httpResource;

    @Override
    public Long saveOrUpdate(EamHierarchyDto dto) {
        Long modelId = dto.getModelId();
        EamHierarchy eamHierarchyDto = new EamHierarchy();
        eamHierarchyDto.setModelId(modelId);
        List<EamHierarchyDto> hierarchyList = queryList(eamHierarchyDto);
        Map<Integer, EamHierarchyDto> hierarchyMap = new HashMap<>();
        if (!BinaryUtils.isEmpty(hierarchyList)) {
            hierarchyMap = hierarchyList.stream().collect(Collectors.toMap(EamHierarchyDto::getDirLvl, each -> each, (k1, k2) -> k1));
            //每次只能存一个层级，不允许重复添加同一层级
            EamHierarchyDto hierarchy = hierarchyMap.get(dto.getDirLvl());
            if (!BinaryUtils.isEmpty(hierarchy) && (dto.getId() == null || !hierarchy.getId().equals(dto.getId()))) {
                throw new ServiceException(THROW_MESSAGE);
            }
        }
        //
        Integer dirLvl = dto.getDirLvl();
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        if (!BinaryUtils.isEmpty(dirLvl) && dirLvl > 0) {
            EamHierarchyDto eamHierarchy = hierarchyMap.get(dto.getDirLvl() - 1);
            if (BinaryUtils.isEmpty(eamHierarchy)) {
                throw new ServiceException(THROW_MESSAGE);
            }
            String upShape = eamHierarchy.getShape();
            //将上一层及的shape判断是否为0，不是0 的话，就拿到里面的id,复制给classId
            if (SHAPE_FLAG.equals(upShape) || BinaryUtils.isEmpty(upShape)) {
                dto.setClassId(0L);
                dto.setInheritShape(upShape);
            } else {
                ProductEle ele = JSON.parseObject(upShape, ProductEle.class);
                dto.setClassId(ele.getId());
                if (!BinaryUtils.isEmpty(ele.getIcon())) {
                    ele.setIcon(ele.getIcon().replaceAll(httpResource, ""));
                    ele.setViewIcon(ele.getViewIcon().replaceAll(httpResource, ""));
                }
                dto.setInheritShape(JSON.toJSONString(ele));
            }
        }
        //TODO 更新绑定当前层级视图的制品id
        /*if(!BinaryUtils.isEmpty(dto.getArtifactId())){
            List<EamDiagramCatalog> privateCatalog = catalogSvc.getByModelIdAndLv(dto.getModelId(), dto.getDirLvl(), LibType.PRIVATE, null);
            List<EamDiagramCatalog> catalogs = catalogSvc.getByModelIdAndLv(dto.getModelId(), dto.getDirLvl(), LibType.DESIGN, null);
            catalogs.addAll(privateCatalog);
            Set<String> diagramIds = catalogs.stream().map(EamDiagramCatalog::getDiagramId).filter(Objects::nonNull).collect(Collectors.toSet());
            if(!BinaryUtils.isEmpty(diagramIds)){
                diagramSvc.updateArtifactId(diagramIds, dto.getArtifactId());
            }
        }*/
        EamHierarchy eamHierarchy = EamUtil.copy(dto, EamHierarchy.class);
        eamHierarchy.setRltList(JSON.toJSONString(dto.getRltList()));
        if (!BinaryUtils.isEmpty(eamHierarchy.getShape())) {
            if (SHAPE_FLAG.equals(eamHierarchy.getShape())) {
                eamHierarchy.setShape(eamHierarchy.getShape());
                eamHierarchy.setEffectClassId(0L);
            } else {
                ProductEle ele = JSON.parseObject(eamHierarchy.getShape(), ProductEle.class);
                if (!BinaryUtils.isEmpty(ele.getIcon())) {
                    ele.setIcon(ele.getIcon().replaceAll(httpResource, ""));
                }
                eamHierarchy.setShape(JSON.toJSONString(ele));
                eamHierarchy.setEffectClassId(ele.getId());
            }
        }
        eamHierarchy.setType(Env.BM_TYPE);
        eamHierarchy.setDomainId(domainId);
        Long aLong = bmHierarchyDao.saveOrUpdate(eamHierarchy);
        //更新下一层级的classId和inheritShape
        int nextDirLvl = eamHierarchy.getDirLvl() + 1;
        if (!BinaryUtils.isEmpty(hierarchyMap)) {
            EamHierarchyDto nextChy = hierarchyMap.get(nextDirLvl);
            if (!BinaryUtils.isEmpty(nextChy)) {
                //看是否有下一层级，将下一层及的“当前层级视图名称”和“自动填充属性”字段值给清空……并保存；
                if (dto.getShape().equals(SHAPE_FLAG) || "".equals(dto.getShape())) {
                    nextChy.setProName("");
                    nextChy.setBelongCIProName("");
                }
                String shape = eamHierarchy.getShape();
                if (SHAPE_FLAG.equals(shape) || "".equals(shape)) {
                    nextChy.setInheritShape(shape);
                    nextChy.setClassId(0L);
                } else if (!BinaryUtils.isEmpty(shape)) {
                    ProductEle ele = JSON.parseObject(shape, ProductEle.class);
                    nextChy.setClassId(ele.getId());
                    if (!BinaryUtils.isEmpty(ele.getIcon())) {
                        ele.setIcon(ele.getIcon().replaceAll(httpResource, ""));
                    }
                    nextChy.setInheritShape(JSON.toJSONString(ele));
                }
                EamHierarchy nextChyCopy = EamUtil.copy(nextChy, EamHierarchy.class);
                bmHierarchyDao.saveOrUpdate(nextChyCopy);
            }
        }
        return aLong;
    }

    @Override
    public List<EamHierarchyDto> queryByLvl(Integer level, Long domainId) {
        Predicate<EamHierarchyDto> predicate;
        if (!BinaryUtils.isEmpty(level)) {
            predicate = each -> level == each.getDirLvl().longValue();
        } else {
            predicate = each -> false;
        }
        List<EamHierarchyDto> list = selectAll(predicate, domainId, null);
        if (BinaryUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list;
    }

    @Override
    public EamHierarchyDto queryByLvlAndModelId(Integer level, Long modelId, Long domainId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", domainId));
        if (!BinaryUtils.isEmpty(modelId)) {
            query.must(QueryBuilders.termQuery(MODEL_ID, modelId));
        }
        if (!BinaryUtils.isEmpty(level)) {
            query.must(QueryBuilders.termQuery(DIR_LEL, level));
        }
        List<EamHierarchy> list = bmHierarchyDao.getListByQuery(query);
        if (BinaryUtils.isEmpty(list)) {
            return null;
        }
        List<EamHierarchyDto> result = replaceIcon(list);
        EamHierarchyDto eamHierarchyDto = result.get(0);
        if (checkExistNextLve(eamHierarchyDto, domainId)) {
            eamHierarchyDto.setNextDirLvl(1);
        }
        if (!BinaryUtils.isEmpty(eamHierarchyDto) && !BinaryUtils.isEmpty(eamHierarchyDto.getModelId())) {
            Long modelIdByEs = eamHierarchyDto.getModelId();
            EamMultiModelHierarchy model = modelHierarchySvc.getModelById(modelIdByEs);
            EamMultiModelHierarchyDto modelDto = EamUtil.copy(model, EamMultiModelHierarchyDto.class);
            eamHierarchyDto.setModelHierarchyDto(modelDto);
        }
        return eamHierarchyDto;
    }

    private boolean checkExistNextLve(EamHierarchyDto eamHierarchyDto, Long domainId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", domainId));
        query.must(QueryBuilders.termQuery(MODEL_ID, eamHierarchyDto.getModelId()));
        query.must(QueryBuilders.termQuery(DIR_LEL, eamHierarchyDto.getDirLvl() + 1));
        return bmHierarchyDao.existByCondition(query);
    }

    private List<EamHierarchyDto> replaceIcon(List<EamHierarchy> list) {
        Map<Integer, EamHierarchy> dirLvlMap = list.stream().collect(Collectors.toMap(EamHierarchy::getDirLvl, each -> each, (k1, k2) -> k2));
        return EamUtil.copy(list, EamHierarchyDto.class, (s, t) -> {
            if (!BinaryUtils.isEmpty(t.getShape()) && !"0".equals(t.getShape())) {
                JSONObject shape = JSON.parseObject(t.getShape());
                if (shape.containsKey(ICON) && !BinaryUtils.isEmpty(shape.get(ICON))) {
                    shape.put(ICON, httpResource + shape.get(ICON));
                    t.setShape(JSON.toJSONString(shape));
                }
            }
            if (!BinaryUtils.isEmpty(t.getInheritShape()) && !"0".equals(t.getInheritShape())) {
                JSONObject shape = JSON.parseObject(t.getInheritShape());
                if (shape.containsKey(ICON) && !BinaryUtils.isEmpty(shape.get(ICON))) {
                    shape.put(ICON, httpResource + shape.get(ICON));
                    t.setInheritShape(JSON.toJSONString(shape));
                }
            }
            if (!BinaryUtils.isEmpty(s.getRltList())) {
                t.setRltList(JSON.parseArray(s.getRltList(), EamArtifactRltVo.class));
            }
            if (!BinaryUtils.isEmpty(t.getDirLvl()) && !BinaryUtils.isEmpty(dirLvlMap.get(t.getDirLvl() + 1))) {
                t.setNextDirLvl(t.getDirLvl() + 1);
            }
        });
    }

    @Override
    public List<EamHierarchyDto> queryList(EamHierarchy cdt) {
        if (cdt == null) {
            cdt = new EamHierarchy();
        }
        if (BinaryUtils.isEmpty(cdt.getDomainId())) {
            cdt.setDomainId(1L);
        }
        Predicate<EamHierarchyDto> predicate = null;
        if (!BinaryUtils.isEmpty(cdt.getDirLvl())) {
            int dirLvl = cdt.getDirLvl();
            predicate = each -> each.getDirLvl() == dirLvl;
        }
        return selectAll(predicate, cdt.getDomainId(), cdt.getModelId());
    }

    @Override
    public List<EamHierarchyDto> queryByModelId(Long modelId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        query.must(QueryBuilders.termQuery(MODEL_ID, modelId));
        List<EamHierarchy> eamList = bmHierarchyDao.getSortListByQuery(1, 1000, query, DIR_LEL, true).getData();
        if (BinaryUtils.isEmpty(eamList)) {
            return Collections.emptyList();
        }
        return replaceIcon(eamList);
    }

    @Override
    public List<EamHierarchyDto> queryByModelIds(List<Long> modelIds) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        query.must(QueryBuilders.termsQuery(MODEL_ID, modelIds));
        Page<EamHierarchy> eamHierarchyPage = bmHierarchyDao.getSortListByQuery(1, 1000, query, DIR_LEL, true);
        if (CollectionUtils.isEmpty(eamHierarchyPage.getData())) {
            return new ArrayList<>();
        }
        return replaceIcon(eamHierarchyPage.getData());
    }


    private List<EamHierarchyDto> selectAll(Predicate<EamHierarchyDto> predicate, Long domainId, Long modelId) {
        try {
            BoolQueryBuilder query = QueryBuilders.boolQuery();
            query.must(QueryBuilders.termQuery("type.keyword", Env.BM_TYPE));
            query.must(QueryBuilders.termQuery("domainId", domainId));
            if (!BinaryUtils.isEmpty(modelId)) {
                query.must(QueryBuilders.termQuery(MODEL_ID, modelId));
            }
            List<EamHierarchy> eamList = bmHierarchyDao.getSortListByQuery(1, 1000, query, DIR_LEL, true).getData();
            List<EamHierarchyDto> result = replaceIcon(eamList);
            if (null != predicate) {
                result = result.stream().filter(predicate).collect(Collectors.toList());
            }
            if (!BinaryUtils.isEmpty(result) && !BinaryUtils.isEmpty(result.get(0).getModelId())) {
                Long modelIdByEs = result.get(0).getModelId();
                EamMultiModelHierarchy model = modelHierarchySvc.getModelById(modelIdByEs);
                EamMultiModelHierarchyDto modelDto = EamUtil.copy(model, EamMultiModelHierarchyDto.class);
                for (EamHierarchyDto dto : result) {
                    dto.setModelHierarchyDto(modelDto);
                }
            }
            return result;
        } catch (Exception e) {
            log.error("查询失败", e);
        }
        return new ArrayList<>();
    }

    @Override
    public Integer deleteById(Long id) {
        //1.查询包含层级信息
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("id", id));
        List<EamHierarchy> listByQuery = bmHierarchyDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(listByQuery)) {
            throw new ServiceException(THROW_MESSAGE);
        }
        EamHierarchy hierarchy = listByQuery.get(0);
        Integer dirLvl = hierarchy.getDirLvl();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("type.keyword", hierarchy.getType()));
        queryBuilder.must(QueryBuilders.termQuery("domainId", hierarchy.getDomainId()));
        queryBuilder.must(QueryBuilders.rangeQuery(DIR_LEL).gte(dirLvl));
        //删除该模型树下的
        queryBuilder.must(QueryBuilders.termQuery(MODEL_ID, hierarchy.getModelId()));
        List<EamHierarchy> deleteList = bmHierarchyDao.getListByQuery(queryBuilder);
        if (CollectionUtils.isEmpty(deleteList)) {
            throw new ServiceException(THROW_MESSAGE);
        }
        return bmHierarchyDao.deleteByQuery(queryBuilder, true);
    }


    @Override
    public Integer deleteNoVerifyById(Long id) {
        //1.查询包含层级信息
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("id", id));
        List<EamHierarchy> listByQuery = bmHierarchyDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(listByQuery)) {
            throw new ServiceException(THROW_MESSAGE);
        }
        EamHierarchy hierarchy = listByQuery.get(0);
        Integer dirLvl = hierarchy.getDirLvl();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("type.keyword", hierarchy.getType()));
        queryBuilder.must(QueryBuilders.termQuery("domainId", hierarchy.getDomainId()));
        queryBuilder.must(QueryBuilders.rangeQuery(DIR_LEL).gte(dirLvl));
        List<EamHierarchy> deleteList = bmHierarchyDao.getListByQuery(queryBuilder);
        if (CollectionUtils.isEmpty(deleteList)) {
            throw new ServiceException(THROW_MESSAGE);
        }
        return bmHierarchyDao.deleteByQuery(queryBuilder, true);
    }

    @Override
    public EamHierarchy queryModeHierarchyByLvl(Integer level, Long domainId, Long modelId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery(DIR_LEL, level));
        query.must(QueryBuilders.termQuery("domainId", domainId));
        query.must(QueryBuilders.termQuery(MODEL_ID, modelId));
        List<EamHierarchy> hierarchies = bmHierarchyDao.getListByQuery(query);
        if (BinaryUtils.isEmpty(hierarchies)) {
            return null;
        }
        return hierarchies.get(0);
    }

    @Override
    public Integer saveOrUpdateBatch(List<EamHierarchy> hierarchyList) {
        return bmHierarchyDao.saveOrUpdateBatch(hierarchyList);
    }

    @Override
    public List<EamHierarchyDto> queryByDiagramId(String diagramId) {
        Long modelId = categorySvc.getModelIdByDiagram(diagramId, LibType.PRIVATE);
        EamHierarchy hierarchy = new EamHierarchy();
        hierarchy.setModelId(modelId);
        return queryList(hierarchy);
    }

    @Override
    public boolean checkPictureUse(String name) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("type.keyword", Env.BM_TYPE));
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        query.must(QueryBuilders.termQuery("markedImg.keyword", name));
        List<EamHierarchy> eamList = bmHierarchyDao.getSortListByQuery(1, 1000, query, DIR_LEL, true).getData();
        return !CollectionUtils.isEmpty(eamList);
    }
}